#include "snakegame.h"
#include <algorithm>
#include <QTime>
#include <cstdlib>

SnakeGame::SnakeGame() : gridWidth(1094 / 20), gridHeight(656 / 20)
{
    // 初始化随机数种子
    qsrand(QTime::currentTime().msec());
    initialize();
}

void SnakeGame::initialize()
{
    snake.clear();
    snake.push_back(QPoint(gridWidth / 2, gridHeight / 2));
    currentDirection = Direction::None;
    nextDirection = Direction::None;
    gameOver = false;
    score = 0;
    generateFood();
}

void SnakeGame::update()
{
    if (currentDirection == Direction::None && nextDirection != Direction::None)
    {
        currentDirection = nextDirection;
    }
    else if (nextDirection != Direction::None)
    {
        // 防止180度转弯
        if ((currentDirection == Direction::Up && nextDirection != Direction::Down) ||
            (currentDirection == Direction::Down && nextDirection != Direction::Up) ||
            (currentDirection == Direction::Left && nextDirection != Direction::Right) ||
            (currentDirection == Direction::Right && nextDirection != Direction::Left))
        {
            currentDirection = nextDirection;
        }
    }

    if (currentDirection != Direction::None)
    {
        moveSnake();
        gameOver = checkCollision();

        // 检查是否吃到食物
        if (snake.front() == food.position)
        {
            // 增加分数 (根据食物类型)
            switch (food.type)
            {
            case FoodType::Yellow:
                score += 1;
                break;
            case FoodType::Blue:
                score += 2;
                break;
            case FoodType::Red:
                score += 3;
                break;
            }

            // 生成新食物
            generateFood();
        }
        else
        {
            // 没吃到食物，移除尾部
            snake.pop_back();
        }
    }
}

bool SnakeGame::isGameOver() const
{
    return gameOver;
}

int SnakeGame::getScore() const
{
    return score;
}

void SnakeGame::setDirection(Direction newDirection)
{
    nextDirection = newDirection;
}

Direction SnakeGame::getDirection() const
{
    return currentDirection;
}

const std::vector<QPoint>& SnakeGame::getSnake() const
{
    return snake;
}

const Food& SnakeGame::getFood() const
{
    return food;
}

void SnakeGame::generateFood()
{
    QPoint newFoodPosition;
    FoodType newFoodType = randomFoodType();

    do
    {
        newFoodPosition.setX(qrand() % gridWidth);
        newFoodPosition.setY(qrand() % gridHeight);
    } while (isSnakeBody(newFoodPosition)); //确保食物不在蛇身上

    food.position = newFoodPosition;
    food.type = newFoodType;
}

bool SnakeGame::checkCollision() const
{
    const QPoint &head = snake.front();
    return isOutOfBounds(head) || isSnakeBody(head, true);
}

void SnakeGame::moveSnake()
{
    QPoint newHead = snake.front();

    switch (currentDirection)
    {
    case Direction::Up:
        newHead.ry()--;
        break;
    case Direction::Down:
        newHead.ry()++;
        break;
    case Direction::Left:
        newHead.rx()--;
        break;
    case Direction::Right:
        newHead.rx()++;
        break;
    case Direction::None:
        break;
    }

    snake.insert(snake.begin(), newHead);//先移动头部
}

bool SnakeGame::isOutOfBounds(const QPoint &point) const
{
    return point.x() < 0 || point.x() >= gridWidth || point.y() < 0 || point.y() >= gridHeight;
} //检测是否撞墙

bool SnakeGame::isSnakeBody(const QPoint &point, bool excludeHead) const
{
    auto begin = excludeHead ? snake.begin() + 1 : snake.begin();
    return std::find(begin, snake.end(), point) != snake.end();
} //检测是否撞到蛇身

FoodType SnakeGame::randomFoodType() const
{
    int randomValue = qrand() % 3;
    switch (randomValue)
    {
    case 0: return FoodType::Yellow;
    case 1: return FoodType::Blue;
    case 2: return FoodType::Red;
    default: return FoodType::Yellow;
    }
} //生成随机颜色的食物
